<template>
    <n-modal
        v-model:show="showModal"
        title="设置规则"
        preset="card"
        style="width: 1200px"
    >
        <n-transfer
            v-model:value="transferModel"
            virtual-scroll
            :options="ruleOptions"
            source-filterable
            :render-target-label="renderTargetLabel"
            style="height: 500px"
        />

        <template #footer>
            <n-flex justify="end">
                <n-button @click="showModal = false">取消</n-button>
                <n-button type="primary" @click="onConfirm">确定</n-button>
            </n-flex>
        </template>
    </n-modal>
</template>

<script setup lang="ts">
import { ICoreRule } from '@/types/core/rule'
import {
    createDiscreteApi,
    NFlex,
    NInput,
    NModal,
    NTransfer,
    TransferOption,
    TransferRenderTargetLabel,
    NButton
} from 'naive-ui'
import { computed, h, nextTick, onUnmounted, reactive, ref, watch } from 'vue'
import { coreRuleList } from '@/apis/core/rule'

const { message } = createDiscreteApi(['message'])

const ruleOptions = reactive<TransferOption[]>([])
const ruleMap = reactive<{ [key: ICoreRule['name']]: ICoreRule }>({})
function getRuleList() {
    coreRuleList()
        .then((res) => {
            res.forEach((item) => {
                const newItem = {
                    value: item.field,
                    label: `${item.name} [ ${item.field} ]`
                }
                ruleOptions.push(newItem)
                ruleMap[item.field] = item
            })

            nextTick(() => handleProps())
        })
        .catch((e: Error) => message.error(e.message))
}

const emits = defineEmits(['update:show', 'update:modelValue'])
const props = defineProps({
    show: {
        type: Boolean,
        default: false
    },
    modelValue: {
        type: String,
        default: () => ''
    }
})

const showModal = computed({
    get: () => props.show,
    set: (val) => emits('update:show', val)
})

// 选中的字段
const transferModel = ref<string[]>([])
const formData = ref<{ [key: ICoreRule['field']]: string }>({})
function handleProps() {
    transferModel.value = []
    formData.value = {}
    const strArr = props.modelValue.split('|')

    strArr.forEach((item) => {
        const itemArr = item.split(':')
        const field = itemArr[0]

        if (!transferModel.value.includes(field))
            transferModel.value.push(field)

        const ruleObj = ruleMap[field]
        if (ruleObj) {
            if (itemArr.length === 1) {
                const oldVal = formData.value[field] || ''
                formData.value[field] = oldVal
            }

            if (itemArr.length === 2) {
                formData.value[field] = itemArr[1]!
            }
        }
    })
}

function handleModel(names: string[]) {
    names = names.filter((n) => n)
    const strArr: string[] = []

    names.forEach((name) => {
        const ruleObj = ruleMap[name]

        if (ruleObj.type === 'boolean') {
            strArr.push(name)
        } else {
            const val = formData.value[name]
            if (val) {
                strArr.push(`${name}:${val}`)
            } else if (ruleObj.nullable) {
                strArr.push(name)
            }
        }
    })

    const str = strArr.length ? strArr.join('|') : ''
    emits('update:modelValue', str)
}

function onConfirm() {
    handleModel(transferModel.value)
    showModal.value = false
}

const stop1 = watch(
    () => props.modelValue,
    () => {
        if (props.show) {
            handleProps()
        }
    },
    { deep: true }
)
const stop2 = watch(
    () => transferModel.value,
    (val) => handleModel(val),
    { deep: true }
)
const stop3 = watch(
    () => props.show,
    (val) => {
        if (val) {
            getRuleList()
        }
    }
)

onUnmounted(() => {
    if (stop1) stop1()
    if (stop2) stop2()
    if (stop3) stop3()
})

const renderTargetLabel: TransferRenderTargetLabel = function ({ option }) {
    const item = ruleMap[option.value]
    return h(
        NFlex,
        {
            vertical: false,
            style: 'padding-top: 5px;padding-bottom:5px',
            align: 'center'
        },
        {
            default: () => [
                h('span', {}, { default: () => option.label }),
                item.type === 'string' &&
                    h(NInput, {
                        placeholder: item.placeholder,
                        clearable: true,
                        value: formData.value[item.field],
                        onUpdateValue(val) {
                            formData.value[item.field] = val
                        },
                        style: 'flex:1'
                    })
            ]
        }
    )
}
</script>
